package me.cabbit.digitone.tones.dots;

import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.awt.image.BufferedImage;
import java.io.FileNotFoundException;

import javax.swing.JCheckBox;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JSpinner;
import javax.swing.SpinnerNumberModel;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

import org.w3c.dom.Element;

import me.cabbit.digitone.support.Strings;
import me.cabbit.digitone.tones.halftone.Halftone;

/**
 * This class provides a visual interface for the DotsTone screentone
 * Basically, it just runs the {@link Halftone} screentone against
 * a black image.
 *
 * @author Arkaid
 */
public class DotsTonePanel extends Halftone implements ChangeListener, ItemListener {

	//------------------------------------------------------------------//
	//--------------------------- properties ---------------------------//
	//------------------------------------------------------------------//

	/** Options panel. This gets added to the main window's toolbox */	
	private JPanel panel;

	/** Strings for internationalization */	
	private Strings strings;
	
	/** Dot size control */	
	private JSpinner spnDotSize;

	/** Horizontal spacing control */	
	private JSpinner spnHSpacing;

	/** Vertical spacing control */	
	private JSpinner spnVSpacing;

	/** angle control */	
	private JSpinner spnAngle;

	/** Color invert control */	
	private JCheckBox chkInvert;
	
	/** A flag to indicate a preset is being loaded. Used to
	 * temporarily refresh the interface without triggering
	 * events
	 */
	private boolean isLoadingPreset;
	
	//------------------------------------------------------------------//
	//----------------------------- methods ----------------------------//
	//------------------------------------------------------------------//

	/**
	 * Constructor. Load the strings and build the options panel.
	 * Load default values from the parent DotsTone class
	 */
	public DotsTonePanel() throws FileNotFoundException 
	{
				
		//load strings
		this.strings = new Strings("lang/DotsTone.strings");
		Strings str = this.strings;
	
		//build panel
		this.panel = new JPanel();
		
		//set layout and constraints
		//Set layout and prepare constraints
		this.panel.setLayout(new GridBagLayout());
		GridBagConstraints c = new GridBagConstraints();
		c.insets = new Insets(3, 3, 3, 3);
		c.fill = GridBagConstraints.HORIZONTAL;

		//Dotsize
		c.gridx = 0; c.gridy = 0; c.weightx = 0.25;
		this.panel.add(new JLabel(str.get("OPTION_DOTSIZE")), c);
		
		c.gridx = 1; c.weightx = 0.75;
		this.spnDotSize = new JSpinner(new SpinnerNumberModel(1, 0, null, 1));
		this.spnDotSize.setValue(this.getMinSize());
		this.spnDotSize.addChangeListener(this);
		this.panel.add(this.spnDotSize, c);

		//horizontal spacing
		c.gridx = 0; c.gridy++; c.weightx = 0.25;
		this.panel.add(new JLabel(str.get("OPTION_HORIZONTAL_SPACING")), c);
		
		c.gridx = 1; c.weightx = 0.75;
		this.spnHSpacing = new JSpinner(new SpinnerNumberModel(0, 0, null, 1));
		this.spnHSpacing.setValue(this.getHorizontalSpacing());
		this.spnHSpacing.addChangeListener(this);
		this.panel.add(this.spnHSpacing, c);
		
		//vertical spacing
		c.gridx = 0; c.gridy++; c.weightx = 0.25;
		this.panel.add(new JLabel(str.get("OPTION_VERTICAL_SPACING")), c);
		
		c.gridx = 1; c.weightx = 0.75;
		this.spnVSpacing = new JSpinner(new SpinnerNumberModel(0, 0, null, 1));
		this.spnVSpacing.setValue(this.getVerticalSpacing());
		this.spnVSpacing.addChangeListener(this);
		this.panel.add(this.spnVSpacing, c);

		//angle
		c.gridx = 0; c.gridy++; c.weightx = 0.25;
		this.panel.add(new JLabel(str.get("OPTION_ANGLE")), c);
		
		c.gridx = 1; c.weightx = 0.75;
		this.spnAngle = new JSpinner(new SpinnerNumberModel(0, 0, 90, 1));
		this.spnAngle.setValue(this.getAngle());
		this.spnAngle.addChangeListener(this);
		this.panel.add(this.spnAngle, c);
		
		//invert colors
		c.gridx = 0; c.gridy = 5; c.weightx = 0.25;
		this.panel.add(new JLabel(str.get("OPTION_INVERT_COLORS")), c);
		
		c.gridx = 1; c.gridy = 5; c.weightx = 0.75;
		this.chkInvert = new JCheckBox();
		this.chkInvert.setSelected(this.getInvertColors());
		this.chkInvert.addItemListener(this);
		this.panel.add(this.chkInvert, c);
		
		//empty panel to push everything to the top
		c.gridx = 0; c.gridy = 6; c.weighty = 1; 
		this.panel.add(new JPanel(), c);
		
		this.isLoadingPreset = false;
	}

	@Override
	public void setSize(int w, int h) {
		super.setSize(w, h);

		//Make a new buffered image to fit the new canvas
		BufferedImage img = new BufferedImage(w, h, BufferedImage.TYPE_BYTE_GRAY);

		//it's just a black square
		Graphics2D g  = img.createGraphics();
		g.setColor(Color.BLACK);
		g.fillRect(0, 0, w, h);
		g.dispose();
		
		this.setSource(img);
	}
	
	@Override
	public String getUID() {
		return "D707DEA0FF5C4E6AAE7AC5E730C043D2";
	}

	@Override
	public JPanel getPanel() 
	{
		return this.panel;
	}

	@Override
	public String getName() 
	{
		return this.strings.get("SCREENTONE_NAME");
	}

	@Override
	public void loadPreset(Element node) 
	{
		//first load the values internally for the screentone
		super.loadPreset(node);
		
		//temporarily turn off updating
		this.isLoadingPreset = true;
						
		this.spnDotSize.setValue(this.getMinSize());
		this.spnHSpacing.setValue(this.getHorizontalSpacing());
		this.spnVSpacing.setValue(this.getVerticalSpacing());
		this.spnAngle.setValue(this.getAngle());
		this.chkInvert.setSelected(this.getInvertColors());
		
		//turn it back on
		this.isLoadingPreset = false;
	}
	
	//------------------------------------------------------------------//
	//------------------------- ChangeListener -------------------------//
	//------------------------------------------------------------------//

	@Override
	public void stateChanged(ChangeEvent event) {
			
		//do nothing if it's loading from a preset
		if (this.isLoadingPreset)
			return;
		
		//according to who raised the event, update the correct property		
		//dot size
		if (event.getSource() == this.spnDotSize) {
			this.setMinSize((int)this.spnDotSize.getValue());
			this.setMaxSize((int)this.spnDotSize.getValue());
		}
		
		//horizontal spacing
		else if (event.getSource() == this.spnHSpacing) 
			this.setHorizontalSpacing((int)this.spnHSpacing.getValue());
		
		//vertical spacing
		else if (event.getSource() == this.spnVSpacing)
			this.setVerticalSpacing((int)this.spnVSpacing.getValue());
		
		//angle
		else if (event.getSource() == this.spnAngle)
			this.setAngle((int)this.spnAngle.getValue());

		//alert of properties changed (refresh display)
		this.raisePropertyChangedEvent();		
	}

	@Override
	public void itemStateChanged(ItemEvent event) {
		//invert colors
		if (event.getSource() == this.chkInvert)
			this.setInvertColors(this.chkInvert.isSelected());

		//alert of properties changed (refresh display)
		this.raisePropertyChangedEvent();		
	}
	
	
}
